#include "qelib.h"
#include "gxcp.h"
#include <pthread.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

QELOG_DOMAIN("dlm");

#define DLM_PORT        60000

typedef struct
{
    WSADATA ws;
    SOCKET sock;
    SOCKADDR_IN host_addr;
    SOCKADDR_IN server_addr;
    gxcp_ctx gxcp;
    qe_list hosts;
} dl_monitor;

static qe_int udp_read(qe_u8 *data, qe_size size, void *user)
{
    int addrlen;
    SOCKADDR_IN addr;
    dl_monitor *dlm = (dl_monitor *)dlm;
    return recvfrom(dlm->sock, (char *)data, size, 0, (struct sockaddr *)&addr, &addrlen);
}

static qe_int udp_write(qe_u8 *data, qe_size size, void *user)
{
    dl_monitor *dlm = (dl_monitor *)user;
    return sendto(dlm->sock, (char *)data, size, 0, (struct sockaddr *)&dlm->host_addr, sizeof(dlm->host_addr));
}

static gxcp_ret readmem_callback(qe_u32 addr, qe_u8 *data, qe_size size, void *user)
{
    dl_monitor *dlm = (dl_monitor *)user;
    return GXCP_SUCCESS;
}

static gxcp_ret writemem_callback(qe_u32 addr, qe_u8 *data, qe_size size, void *user)
{
    dl_monitor *dlm = (dl_monitor *)user;
    return GXCP_SUCCESS;
}

static void *host_task(void *args)
{
    int n;
    int addrlen;
    char rxbuf[1500];
    SOCKADDR_IN addr;


    addrlen = sizeof(addr);

    while (1) {


    }
}

static qe_ret dlm_init(dl_monitor *dlm)
{
    int addrlen;
    DWORD val = 1000;
    gxcp_io udp_io;
    gxcp_bootstrap_regs bsr;
    gxcp_callback callback;

    qe_list_init(&dlm->hosts);

    WSAStartup(MAKEWORD(2, 2), &dlm->ws);

    dlm->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (!dlm->sock) {
        qe_error("socket create error");
        return qe_err_common;
    }

    dlm->server_addr.sin_family = AF_INET;
    dlm->server_addr.sin_addr.s_addr = inet_addr("192.168.0.201");
    dlm->server_addr.sin_port = htons(DLM_PORT);
    addrlen = sizeof(dlm->server_addr);
    bind(dlm->sock, (const struct sockaddr *)&dlm->server_addr, addrlen);

    setsockopt(dlm->sock, SOL_SOCKET, SO_RCVTIMEO, (const char*)&val, sizeof(val));

    udp_io.read = udp_read;
    udp_io.write = udp_write;

    callback.readmem = readmem_callback;
    callback.writemem = writemem_callback;

    qe_memset(&bsr, 0, sizeof(bsr));
    bsr.protocol_version = 0x00010000;
    qe_sprintf(bsr.manufacturer_name, "HYST");
    qe_sprintf(bsr.model_name, "ASTX");
    qe_sprintf(bsr.device_version, "KGD-ASTX-LINK");
    qe_sprintf(bsr.serial_number, "132567653");
    qe_sprintf(bsr.device_version, "v1.0.0");
    bsr.device_capability = 1;
    bsr.max_dev_response_time = 1000;

    gxcp_init(&dlm->gxcp, 1500, dlm);
    gxcp_set_io(&dlm->gxcp, &udp_io);
    gxcp_set_callback(&dlm->gxcp, &callback);
    gxcp_set_bootstrap(&dlm->gxcp, &bsr);

    return qe_ok;
}

int main(int argc, char *argv[])
{
    int n;
    int addrlen;
    char rxbuf[1500];
    SOCKET client_socket;
    SOCKADDR_IN client_addr;

    qelog_init(QELOG_DEBUG, QELOG_CL|QELOG_DATE|QELOG_DM|QELOG_LV);

    dl_monitor *dlm = qe_malloc(sizeof(dl_monitor));
    if (!dlm) {
        qe_error("alloc monitor failed");
        return -1;
    }

    dlm_init(dlm);

    qe_info("dlm start run");

    addrlen = sizeof(client_addr);

    while (1) {

        n = recvfrom(dlm->sock, rxbuf, sizeof(rxbuf), 0, (struct sockaddr *)&dlm->host_addr, &addrlen);
        if (n > 0) {
            qe_debug("recv data");
            gxcp_rx_handle(&dlm->gxcp, rxbuf, n);
        }
    }

    return 0;
}